import json
import os
import threading
import time
from fastapi import FastAPI ,WebSocket , Request
from apilib.component import compManager,TComp


class TWsSessions :
    def __init__(self):
        self.sessions ={}
        self.eventHandlers={
            "onMessage": None
        }
    async def acceptWs(self , websocket: WebSocket):
        try:
            await websocket.accept()
            wsId = str(websocket)[1:-1].split(' ')[-1]
            while True:
                try:
                    time.sleep(0.01)
                    success , msg = await self.readMsg(websocket)
                    if success :
                        if msg['ac'] =='regist':
                            self.sessions[wsId] = {
                                "wsId": wsId,
                                "peerId": msg['data']['peerId'],
                                "peerType": msg['data']['peerType'],
                                "subAcs": msg['data']['subAcs'],
                                "ws": websocket,
                                "registTime": time.time()
                            }
                            peerMsg = self.getPeersMsg()
                            await self.sendMsg(peerMsg)
                        else:
                            await  self.sendMsg(msg)
                            if self.eventHandlers['onMessage']!=None:
                                try:
                                    await  self.eventHandlers['onMessage'](msg)
                                except Exception as erAc:
                                    print("acceptWs event error" , erAc)
                    else:
                        if wsId in self.sessions.keys():
                            del self.sessions[wsId]
                        try:
                            await websocket.close(1001 , 'message error')
                        except Exception as errClose:
                            print('websocket.close error.' , errClose)
                        peerMsg = self.getPeersMsg()
                        await self.sendMsg(peerMsg)
                        break
                except Exception as erRead:
                    print('wsAccept read' , erRead)
        except Exception as er:
            print('wsAccept',er)
    async def readMsg(self , websocket: WebSocket):
        res = {}
        success = False
        try:
            wsState = str( websocket.client_state)
            if wsState  == 'WebSocketState.CONNECTED' :
                recData = await websocket.receive_text()
                try:
                    msg = json.loads(recData)
                    success = "ac" in msg.keys() and "data" in msg.keys()
                    if success :
                        res = msg
                except Exception as erDecode:
                    print(erDecode , 'decoder')
        except Exception as er:
            print('wsAccept readMsg',er)
        return  success , res
    def getPeersMsg(self):
        return {
            "ac":"peerChanged",
            "data":[
                {
                    "wsId": s["wsId"],
                    "peerId": s['peerId'],
                    "peerType": s['peerType'],
                    "subAcs": s['subAcs'],
                    "registTime": s["registTime"]
                }
                for s in self.sessions.values()
            ]
        }
    async def sendMsg(self , msg):
        res = {}
        success = False
        try:
            content = json.dumps(msg , ensure_ascii=False)
            recWs =[
                s['ws']
                for s in self.sessions.values()
                if msg['ac'] in  s['subAcs']
            ]
            for ws in recWs:
                try:
                    wsState = str(ws.client_state)
                    if wsState == 'WebSocketState.CONNECTED':
                        await ws.send_text(content)
                except Exception as sendErr:
                    print('send msg err' , sendErr)
        except Exception as er:
            print('ws regist',er)
        return  success , res
class TPluginTimer( TComp):
    def __init__(self):
        super().__init__()
        self.compSettings={}
        self.handlers={
            "action" : self.action,
            "getStatus": self.getStatus
        }
        self.eventHandler ={
            "action":None
        }
        self.wsSessions = TWsSessions()
        self.wsSessions.eventHandlers['onMessage'] = self.onWsSessionMsg

        self.clockType = 0 #0-外部授时；1-系统授时
        self.preThreshold = 45
        self.gameThreshold = 81

        self.timerInfo = {
            "clockTime":0 ,
            "sysTime": 0 ,
            "preTime":{
                "start":0 ,
                "end":0 ,
                "pauses":[] ,
                "active": 0
            } ,
            "gameTime":{
                "start":0 ,
                "end":0 ,
                "pauses":[] ,
                "active": 0
            } ,
            "gate":{
                "in":[],
                "out":[],
            },
            "points":[]
        }
        self.timerStatus = {}

    def compInit(self):
        super().compInit()
        try:
            self.clockType= self.compSettings['clockType']
            self.preThreshold= self.compSettings['preThreshold']
            self.gameThreshold= self.compSettings['gameThreshold']
            self.timerInfo ['points']=[
                {
                    "order":pt['order'] ,
                    "code":pt['code'] ,
                    "time":{
                        "success":0,
                        "fail":0,
                        "refuse":0
                    }
                }
                for pt in self.compSettings['points']
            ]
        except Exception as er:
            self.manager.log(er)

    def getNowTime(self ):
        return  self.timerInfo['clockTime'] if self.clockType == 0 else time.time()
    def getTm(self , acTime=0):
        return acTime if acTime>0 else self.getNowTime()
    def getNetTime(self , clockCode):
        res = 0
        try:
            if clockCode  in self.timerInfo.keys():
                clock = self.timerInfo[clockCode ]
                start = clock['start']
                if start>0:
                    end = self.getTm(clock['end'])
                    total = end - start
                    pasuseTm = 0
                    if len(clock['pauses'])>0:
                        for i in range(len(clock['pauses'])):
                            pasuseTm = pasuseTm + clock['pauses'][i] * (-1 if i%2==0 else 1 )
                        if len(clock['pauses'])%2==1:
                            pasuseTm = pasuseTm+ self.getTm(0)
                    res = total - pasuseTm
        except Exception as er:
            self.manager.log(er)
        return res

    def updateStatus(self ):
        try:
            pre_status = 0
            if self.timerInfo['preTime']["start"]==0 :
                pre_status = 0
            elif self.timerInfo['preTime']["end"]>0 :
                pre_status = 3
            elif len(self.timerInfo['preTime']["pauses"])>0 :
                pre_status = 2
            else:
                pre_status = 1
            game_status = 0
            if self.timerInfo['gameTime']["start"]==0 :
                game_status = 0
            elif self.timerInfo['gameTime']["end"]>0 :
                game_status = 3
            elif len(self.timerInfo['gameTime']["pauses"])>0 :
                game_status = 2
            else:
                game_status = 1
            res={
                "timer_code" : self.code ,
                "clock_time" : self.timerInfo['clockTime'] ,
                "sys_time" : self.timerInfo['sysTime'] ,
                "now_time" : self.getNowTime(),
                "pre_status" : pre_status,
                "pre_start" : self.timerInfo['preTime']["start"] ,
                "pre_end" : self.timerInfo['preTime']["end"] ,
                "pre_netTime" : self.getNetTime('preClock'),
                "preThreshold" : self.compSettings['preThreshold'],
                "game_status" : game_status,
                "game_start" : self.timerInfo['gameTime']["start"] ,
                "game_end" : self.timerInfo['gameTime']["end"] ,
                "game_netTime" : self.getNetTime('gameClock'),
                "gameThreshold" : self.compSettings['gameThreshold'],
                "gate_in_time" : self.timerInfo['gate']['in'],
                "gate_out_time" : self.timerInfo['gate']['out'],
            }
            self.timerStatus = res
        except Exception as er:
            self.manager.log(er)
        return self.timerStatus
        return  self.timerStatus
    def saveStatus(self ):
        try:
            pass
        except Exception as er:
            self.manager.log(er)
        return  self.timerStatus
    def trigger(self , acCode , acTm , tag={}):
        try:
            self.updateStatus()
            self.saveStatus()
            if self.eventHandler['action']!=None:
                try:
                    self.eventHandler['action']( acCode , acTm , tag)
                except Exception as eer:
                    self.manager.log(eer)
            if acCode=='acPreStart':
                (threading.Thread( target= self.loopOnStartPre , daemon=True)).start()
            elif acCode=='acGameStart':
                (threading.Thread( target= self.loopOnStartGame , daemon=True)).start()
            elif acCode=='acPassGate':
                if tag[''] == 'in'  :
                    self.action('acGameStart', acTm)
                elif tag[''] == 'out' :
                    self.action('acGameEnd', acTm)
            elif acCode=='acPreEnd':
                self.action('acGameStart', acTm)
        except Exception as er:
            self.manager.log(er)
    def loopOnStartPre(self ):
        try:
            actived =  self.timerInfo['preTime']['active']
            interval = self.compSettings['interval']
            threshold = self.compSettings['preThreshold']
            while ( actived>0 ):
                try:
                    time.sleep(interval)
                    netTime = self.getNetTime()
                    if netTime> threshold:
                        self.action('acPreEnd' , self.getTm(0))

                except Exception as err:
                    self.manager.log(err)
        except Exception as er:
            self.manager.log(er)
        finally:
            self.timerInfo['preTime']['active'] = 0
    def loopOnStartGame(self ):
        try:
            pass
        except Exception as er:
            self.manager.log(er)
        finally:
            self.timerInfo['gameTime']['active'] = 0

    def getInitTimerInfo (self ):
        return   {
            "clockTime":0 ,
            "sysTime": 0 ,
            "preTime":{
                "start":0 ,
                "end":0 ,
                "pauses":[]
            } ,
            "gameTime":{
                "start":0 ,
                "end":0 ,
                "pauses":[]
            } ,
            "gateInTime":[],
            "gateOutTime":[],
            "points":[]
        }

    def action(self , acCode , acTime =0 , gateCode= "",  pointOrder =0 , pointStatus =0):
        try:
            tm = self.getTm(acTime)
            # 系统复位
            if acCode == "acReset":
                self.timerInfo = self.getInitTimerInfo()
                self.compInit()
                self.trigger(acCode , acTime)
            # 系统授时
            elif acCode == "acSetClockTime":
                self.timerInfo['clockTime'] = acTime
                self.timerInfo['sysTime'] = time.time()
                self.trigger(acCode , acTime)
            # 45倒计时
            elif acCode=="acPreStart":
                preStart = self.timerInfo['preTime']['start']
                if preStart==0:
                    self.timerInfo['preTime']['start'] = tm
                    self.timerInfo['preTime']['end'] = 0
                    self.timerInfo['preTime']['pauses'].clear()
                    self.trigger(acCode , acTime)
            elif acCode=="acPreSwitchPause":
                preStart = self.timerInfo['preTime']['start']
                preEnd = self.timerInfo['preTime']['end']
                if preStart>0 and preEnd==0:
                    self.timerInfo['preTime']['pauses'].append(tm)
                    self.trigger(acCode , acTime)
            elif acCode=="acPreEnd":
                preStart = self.timerInfo['preTime']['start']
                preEnd = self.timerInfo['preTime']['end']
                if preStart>0 and preEnd==0:
                    self.timerInfo['preTime']['end'] = tm
                    self.trigger(acCode , acTime)
            # 比赛计时
            elif acCode=="acGameStart":
                gameStart = self.timerInfo['gameTime']['start']
                if gameStart==0:
                    self.timerInfo['gameTime']['start'] = tm
                    self.timerInfo['gameTime']['end'] = 0
                    self.timerInfo['gameTime']['pauses'].clear()
                    self.timerInfo ['points']=[
                        {
                            "order":pt['order'] ,
                            "code":pt['code'] ,
                            "time":{
                                "success":0,
                                "fail":0,
                                "refuse":0
                            }
                        }
                        for pt in self.compSettings['points']
                    ]
                    self.trigger(acCode , acTime)
            elif acCode=="acGameSwitchPause":
                gameStart = self.timerInfo['gameTime']['start']
                gameEnd = self.timerInfo['gameTime']['end']
                if gameStart>0 and gameEnd==0:
                    self.timerInfo['gameTime']['pauses'].append(tm)
                    self.trigger(acCode , acTime)
            elif acCode=="acGameEnd":
                gameStart = self.timerInfo['gameTime']['start']
                gameEnd = self.timerInfo['gameTime']['end']
                if gameStart>0 and gameEnd==0:
                    self.timerInfo['gameTime']['end'] = tm
                    self.trigger(acCode , acTime)
            # 过门
            elif acCode=="acPassGate":
                if gateCode=='in' :
                    gameStart = self.timerInfo['gameTime']['start']
                    gameEnd = self.timerInfo['gameTime']['end']
                    if gameStart==0 and gameEnd ==0:
                        self.timerInfo['gate']["in"].append(tm)
                        self.trigger(acCode , acTime , {"gateCode" , gateCode})
                elif gateCode =='out':
                    gameStart = self.timerInfo['gameTime']['start']
                    gameEnd = self.timerInfo['gameTime']['end']
                    unPassPointNum = len(
                        [x for x in self.timerInfo['points'] if x['time']['success']==0 and x['time']['fail']==0 ]
                    )
                    if gameStart>=0 and gameEnd==0 and unPassPointNum == 0 :
                        self.timerInfo['gate']["out"].append(tm)
                        self.trigger(acCode , acTime , {"gateCode" , gateCode})
            # 障碍
            elif acCode=="acPoint":
                point = self.timerInfo["points"][pointOrder]
                if pointStatus in point['time'].keys():
                    point['time'][pointOrder] = tm

                    self.trigger(acCode , acTime , {
                        "order": pointOrder ,
                        "status": pointStatus,
                        "point": point
                    })
        except Exception as er:
            self.manager.log(er)

    def getStatus (self ,updateFlag = 0 ):
        if updateFlag :
            self.updateStatus()
        return   self.timerStatus
    async def onWsSessionMsg(self , msg):
        try:
            cmdAcs=[ "C"+ str(i) for i in range(8)]
            cmdAcs.append('RT')
            if msg['ac'] in cmdAcs:
                code = msg['ac']
                tm = msg['data']['t']
                self.action('acSetClockTime' , tm)
                if code[0]=='C':
                    print('signal code:' , code , tm)
        except Exception as er:
            self.manager.log(er)

_settings = {
    "clockType": 0 , #0-外部授时，1-系统授时
    "interval":0.01,
    "preThreshold": 45 ,
    "gameThreshold": 81 ,
    "penTime": 1 ,
    "penPoint": 4 ,
    "penRefuse": 4 ,
    "points":[
        {"order": 1 , "code":"1"} ,
        {"order": 2 , "code":"2"} ,
        {"order": 3 , "code":"3"} ,
        {"order": 4 , "code":"4"} ,
        {"order": 5 , "code":"5"} ,
        {"order": 6 , "code":"6"} ,
        {"order": 7 , "code":"7"} ,
        {"order": 8 , "code":"8"} ,
        {"order": 9 , "code":"9"} ,
        {"order": 10 , "code":"10"} ,
        {"order": 11 , "code":"11"} ,
        {"order": 12 , "code":"12"} ,
    ]
}
compManager.registComponentType('TPluginTimer' , TPluginTimer , _settings)